package study.wy.sparsearray;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 稀疏数组
 * @author wy
 */
public class SparseArray {
    public static void main(String[] args) {
        //定义原始数据
        int[][] data = new int[10][10];
        //赋值
        data[1][2] = 1;
        data[2][3] = 2;
        data[3][5] = 4;
        data[8][2] = 5;
        data[6][0] = 8;

        System.out.println("原始数据↓");
        //输出原始数据
        for (int[] row : data) {
            for (int col : row) {
                System.out.print(col + "    ");
            }
            System.out.println();
        }

        System.out.println();

        //获取稀疏数组
        int[][] sparseArray = getSparseArray(data);

        System.out.println("稀疏数组↓");
        //输出稀疏数组
        for (int[] row : sparseArray) {
            for (int col : row) {
                System.out.print(col + "    ");
            }
            System.out.println();
        }

        //将稀疏数组写入文件
        writeFileForSparseArray(sparseArray);

        System.out.println();

        //从文件中读取稀疏数组
        sparseArray = readFileForSparseArray(new File("src/study/wy/sparsearray/file"));

        System.out.println("从文本文件中读取的稀疏数组↓");
        for (int[] row : sparseArray) {
            for (int col : row) {
                System.out.print(col + "    ");
            }
            System.out.println();
        }

        System.out.println();

        //获取原始数据
        int[][] parseData = getData(sparseArray);

        //输出原始数据
        for (int[] row : parseData) {
            for (int col : row) {
                System.out.print(col + "    ");
            }
            System.out.println();
        }

        //将稀疏数组序列化到文件中
        writeSerializeForSparseArray(sparseArray);

        System.out.println();

        //从序列化文件中读取稀疏数组
        sparseArray = readSparseArrayForSerializeFile(new File("src/study/wy/sparsearray/serialize.ser"));

        System.out.println("从序列化文件中读取的稀疏数组↓");

        for (int[] row : sparseArray) {
            for (int col : row) {
                System.out.print(col + "    ");
            }
            System.out.println();
        }

        System.out.println();

        //获取原始数据
        parseData = getData(sparseArray);

        //输出原始数据
        for (int[] row : parseData) {
            for (int col : row) {
                System.out.print(col + "    ");
            }
            System.out.println();
        }
    }

    /**
     * 将二维数组转化为稀疏数组
     * @param data  原始数据
     * @return      稀疏数组
     */
    public static int[][] getSparseArray(int[][] data){
        //记录原始数据中有效数据的个数
        int sum = 0;
        for (int[] row : data) {
            for (int col : row) {
                if (col != 0)
                    sum++;
            }
        }

        //定义稀疏数组
        int[][] sparseArray = new int[sum+1][3];
        //稀疏数组第一行数据赋值
        sparseArray[0][0] = data.length;
        sparseArray[0][1] = data[0].length;
        sparseArray[0][2] = sum;

        //为稀疏数组其余数据赋值
        //记录稀疏数组已经记录的行数
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] != 0) {
                    index++;
                    sparseArray[index][0] = i;
                    sparseArray[index][1] = j;
                    sparseArray[index][2] = data[i][j];
                }
            }
        }

        return sparseArray;
    }

    /**
     * 将稀疏数组转回原始数组
     * @param sparseArray   稀疏数组
     * @return              原始数据
     */
    public static int[][] getData(int[][] sparseArray){
        //定义原始数组
        int[][] data = new int[sparseArray[0][0]][sparseArray[0][1]];

        //为原始数组赋值
        for (int i = 1; i < sparseArray.length; i++) {
            data[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
        }

        return data;
    }

    /**
     * 将稀疏数组写入文件
     * @param sparseArray   稀疏数组
     */
    public static void writeFileForSparseArray(int[][] sparseArray){
        File file = new File("src/study/wy/sparsearray/file");
        try (FileWriter writer = new FileWriter(file)) {
            for (int[] row : sparseArray) {
                for (int col : row) {
                    writer.write(col + ",");
                }
                writer.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从文件中读取稀疏数组
     * @param file  稀疏数组所在文件
     * @return      读取的稀疏数组
     */
    public static int[][] readFileForSparseArray(File file){
        int[][] sparseArray = null;
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line = reader.readLine();
            List<String> lineList = new ArrayList<>();
            lineList.add(line);
            while ((line = reader.readLine()) != null) {
                lineList.add(line);
            }
            sparseArray = new int[lineList.size()][3];
            List<int[]> collect = lineList.stream().map(str -> {
                String[] split = str.split(",");
                return new int[]{Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])};
            }).collect(Collectors.toList());
            int index = 0;
            for (int[] row : collect) {
                sparseArray[index][0] = row[0];
                sparseArray[index][1] = row[1];
                sparseArray[index][2] = row[2];
                index++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sparseArray;
    }

    /**
     * 将稀疏数组序列化到文件中
     * @param sparseArray   稀疏数组
     */
    public static void writeSerializeForSparseArray(int[][] sparseArray){
        File serializeFile = new File("src/study/wy/sparsearray/serialize.ser");
        try (ObjectOutputStream serialize = new ObjectOutputStream(new FileOutputStream(serializeFile))) {
            serialize.writeObject(sparseArray);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从序列化文件中读取稀疏数组
     * @param serializeFile     序列化文件
     * @return                  读取的稀疏数组
     */
    public static int[][] readSparseArrayForSerializeFile(File serializeFile){
        int[][] sparseArray = null;
        try (ObjectInputStream serialize = new ObjectInputStream(new FileInputStream(serializeFile))) {
            sparseArray = (int[][]) serialize.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return sparseArray;
    }
}
